﻿using System;
using System.Collections.Generic;
using System.Xml.XPath;
using NCrontab;

namespace GianosNET.Services.CronSVC.classes
{
    public abstract class Task
    {
        public enum TaskTypeEnum
        {
            SqlCmd,
            WebserviceMethod
        }

        public class AdditionalAttributes : Dictionary<string, string>
        {
            public void Populate(XPathNavigator task)
            {
                
            }
        }

        public string ID { get; private set; }
        public TaskTypeEnum Type { get; private set; }
        public bool Enabled { get; set; }
        public bool ExecuteImmediately { get; set; }

        public DateTime? LastExecution
        {
            get { return lastExecution; }
            set
            {
                lastExecution = value;
                if (crontabSchedule != null)
                    NextExecution = crontabSchedule.GetNextOccurrence(lastExecution.GetValueOrDefault(DateTime.Now));
            }
        }

        public DateTime NextExecution { get; private set; }

        public AdditionalAttributes Parameters { get; protected set; }

        private CrontabSchedule crontabSchedule;
        private DateTime? lastExecution;

        protected virtual void PopulateAdditionalParameters(XPathNavigator task)
        {
            if (Parameters!=null)
                foreach (string key in new List<string>(Parameters.Keys))
                    if (Parameters[key] == null)
                        Parameters[key] = task.GetAttribute(key, "");
        }

        protected Task(string id, TaskTypeEnum type, bool enabled, string crontabString, bool executeImmediately)
        {
            ID = id;
            Type = type;
            Enabled = enabled;
            ExecuteImmediately = executeImmediately;

            ValueOrError<CrontabSchedule> res = CrontabSchedule.TryParse(crontabString);
            if (res.HasValue)
            {
                crontabSchedule = res.Value;
                NextExecution = executeImmediately
                                    ? DateTime.Now.AddSeconds(-1)
                                    : crontabSchedule.GetNextOccurrence(DateTime.Now);
            }
            else
            {
                throw new Exception("Crontab schedule definition error", res.Error);
            }
        }

        public static Task CreateInstance(XPathNavigator task)
        {
            Task t;

            string id = task.GetAttribute("ID", "");
            string type = task.GetAttribute("type", "");
            bool enabled = (task.GetAttribute("enabled", "") ?? "").ToLower() == "true";
            bool executeImmediately = (task.GetAttribute("executeImmediately", "") ?? "").ToLower() == "true";
            string crontabString = task.GetAttribute("crontab", "");

            switch (type)
            {
                case "sql_cmd":
                    t = new SqlCmdTask(id, TaskTypeEnum.SqlCmd, enabled, crontabString, executeImmediately);
                    break;

                //case "ws":
                //    t = new WsMethodTask(id, TaskTypeEnum.WebserviceMethod, enabled, crontabString, executeImmediately);
                //    break;

                default:
                    throw new Exception("Task type non riconosciuto");

            }

            t.PopulateAdditionalParameters(task);

            return t;
        }

        public bool TimeForExecution
        {
            get
            {
                if (Enabled && crontabSchedule != null)
                    return NextExecution <= DateTime.Now;
                return false;
            }
        }

        public virtual string Execute()
        {
            LastExecution = DateTime.Now;
            return "";
        }

        public void SetNextExecution(DateTime d)
        {
            NextExecution = d;
        }
    }
}
